home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / portmap / portmap.c < prev   
Encoding:
C/C++ Source or Header  |  1988-11-17  |  11.1 KB  |  476 lines

  1. /* @(#)portmap.c    1.1 87/11/04 3.9 RPCSRC */
  2. #ifndef lint
  3. static    char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
  4. #endif
  5.  
  6. /*
  7.  * Copyright (c) 1984 by Sun Microsystems, Inc.
  8.  */
  9.  
  10. /*
  11.  * portmap.c, Implements the program,version to port number mapping for
  12.  * rpc.
  13.  */
  14.  
  15. /*
  16.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  17.  * unrestricted use provided that this legend is included on all tape
  18.  * media and as a part of the software program in whole or part.  Users
  19.  * may copy or modify Sun RPC without charge, but are not authorized
  20.  * to license or distribute it to anyone else except as part of a product or
  21.  * program developed by the user.
  22.  * 
  23.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  24.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  25.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  26.  * 
  27.  * Sun RPC is provided with no support and without any obligation on the
  28.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  29.  * modification or enhancement.
  30.  * 
  31.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  32.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  33.  * OR ANY PART THEREOF.
  34.  * 
  35.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  36.  * or profits or other special, indirect and consequential damages, even if
  37.  * Sun has been advised of the possibility of such damages.
  38.  * 
  39.  * Sun Microsystems, Inc.
  40.  * 2550 Garcia Avenue
  41.  * Mountain View, California  94043
  42.  */
  43.  
  44. #include <rpc/rpc.h>
  45. #include <rpc/pmap_prot.h>
  46. #include <stdio.h>
  47. #include <netdb.h>
  48. #include <sys/socket.h>
  49. #include <sys/time.h>
  50. #include <sys/ioctl.h>
  51. #include <sys/wait.h>
  52.  
  53. char *malloc();
  54. int reg_service();
  55. struct pmaplist *pmaplist;
  56. static int debugging = 0;
  57.  
  58. main()
  59. {
  60.     SVCXPRT *xprt;
  61.     int sock, pid, t;
  62.     struct sockaddr_in addr;
  63.     int len = sizeof(struct sockaddr_in);
  64.     register struct pmaplist *pml;
  65.  
  66. #ifndef DEBUG
  67.     pid = fork();
  68.     if (pid < 0) {
  69.         perror("portmap: fork");
  70.         exit(1);
  71.     }
  72.     if (pid != 0)
  73.         exit(0);
  74.     for (t = 0; t < 20; t++)
  75.         close(t);
  76.      open("/", 0);
  77.      dup2(0, 1);
  78.      dup2(0, 2);
  79.      t = open("/dev/tty", 2);
  80.      if (t >= 0) {
  81.          ioctl(t, TIOCNOTTY, (char *)0);
  82.          close(t);
  83.      }
  84. #endif
  85.     if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
  86.         perror("portmap cannot create socket");
  87.         exit(1);
  88.     }
  89.  
  90.     addr.sin_addr.s_addr = 0;
  91.     addr.sin_family = AF_INET;
  92.     addr.sin_port = htons(PMAPPORT);
  93.     if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
  94.         perror("portmap cannot bind");
  95.         exit(1);
  96.     }
  97.  
  98.     if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
  99.         fprintf(stderr, "couldn't do udp_create\n");
  100.         exit(1);
  101.     }
  102.     /* make an entry for ourself */
  103.     pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
  104.     pml->pml_next = 0;
  105.     pml->pml_map.pm_prog = PMAPPROG;
  106.     pml->pml_map.pm_vers = PMAPVERS;
  107.     pml->pml_map.pm_prot = IPPROTO_UDP;
  108.     pml->pml_map.pm_port = PMAPPORT;
  109.     pmaplist = pml;
  110.  
  111.     if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  112.         perror("portmap cannot create socket");
  113.         exit(1);
  114.     }
  115.     if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
  116.         perror("portmap cannot bind");
  117.         exit(1);
  118.     }
  119.     if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
  120.         == (SVCXPRT *)NULL) {
  121.         fprintf(stderr, "couldn't do tcp_create\n");
  122.         exit(1);
  123.     }
  124.     /* make an entry for ourself */
  125.     pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
  126.     pml->pml_map.pm_prog = PMAPPROG;
  127.     pml->pml_map.pm_vers = PMAPVERS;
  128.     pml->pml_map.pm_prot = IPPROTO_TCP;
  129.     pml->pml_map.pm_port = PMAPPORT;
  130.     pml->pml_next = pmaplist;
  131.     pmaplist = pml;
  132.  
  133.     (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
  134.     svc_run();
  135.     fprintf(stderr, "run_svc returned unexpectedly\n");
  136.     abort();
  137. }
  138.  
  139. static struct pmaplist *
  140. find_service(prog, vers, prot)
  141.     u_long prog;
  142.     u_long vers;
  143. {
  144.     register struct pmaplist *hit = NULL;
  145.     register struct pmaplist *pml;
  146.  
  147.     for (pml = pmaplist; pml != NULL; pml = pml->pml_next) {
  148.         if ((pml->pml_map.pm_prog != prog) ||
  149.             (pml->pml_map.pm_prot != prot))
  150.             continue;
  151.         hit = pml;
  152.         if (pml->pml_map.pm_vers == vers)
  153.             break;
  154.     }
  155.     return (hit);
  156. }
  157.  
  158. /* 
  159.  * 1 OK, 0 not
  160.  */
  161. reg_service(rqstp, xprt)
  162.     struct svc_req *rqstp;
  163.     SVCXPRT *xprt;
  164. {
  165.     struct pmap reg;
  166.     struct pmaplist *pml, *prevpml, *fnd;
  167.     int ans, port;
  168.     caddr_t t;
  169.     
  170. #ifdef DEBUG
  171.     fprintf(stderr, "server: about do a switch\n");
  172. #endif
  173.     switch (rqstp->rq_proc) {
  174.  
  175.     case PMAPPROC_NULL:
  176.         /*
  177.          * Null proc call
  178.          */
  179.         if ((!svc_sendreply(xprt, xdr_void, NULL)) && debugging) {
  180.             abort();
  181.         }
  182.         break;
  183.  
  184.     case PMAPPROC_SET:
  185.         /*
  186.          * Set a program,version to port mapping
  187.          */
  188.         if (!svc_getargs(xprt, xdr_pmap, ®))
  189.             svcerr_decode(xprt);
  190.         else {
  191.             /*
  192.              * check to see if already used
  193.              * find_service returns a hit even if
  194.              * the versions don't match, so check for it
  195.              */
  196.             fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
  197.             if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
  198.                 if (fnd->pml_map.pm_port == reg.pm_port) {
  199.                     ans = 1;
  200.                     goto done;
  201.                 }
  202.                 else {
  203.                     ans = 0;
  204.                     goto done;
  205.                 }
  206.             } else {
  207.                 /* 
  208.                  * add to END of list
  209.                  */
  210.                 pml = (struct pmaplist *)
  211.                     malloc((u_int)sizeof(struct pmaplist));
  212.                 pml->pml_map = reg;
  213.                 pml->pml_next = 0;
  214.                 if (pmaplist == 0) {
  215.                     pmaplist = pml;
  216.                 } else {
  217.                     for (fnd= pmaplist; fnd->pml_next != 0;
  218.                         fnd = fnd->pml_next);
  219.                     fnd->pml_next = pml;
  220.                 }
  221.                 ans = 1;
  222.             }
  223.         done:
  224.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
  225.                 debugging) {
  226.                 fprintf(stderr, "svc_sendreply\n");
  227.                 abort();
  228.             }
  229.         }
  230.         break;
  231.  
  232.     case PMAPPROC_UNSET:
  233.         /*
  234.          * Remove a program,version to port mapping.
  235.          */
  236.         if (!svc_getargs(xprt, xdr_pmap, ®))
  237.             svcerr_decode(xprt);
  238.         else {
  239.             ans = 0;
  240.             for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
  241.                 if ((pml->pml_map.pm_prog != reg.pm_prog) ||
  242.                     (pml->pml_map.pm_vers != reg.pm_vers)) {
  243.                     /* both pml & prevpml move forwards */
  244.                     prevpml = pml;
  245.                     pml = pml->pml_next;
  246.                     continue;
  247.                 }
  248.                 /* found it; pml moves forward, prevpml stays */
  249.                 ans = 1;
  250.                 t = (caddr_t)pml;
  251.                 pml = pml->pml_next;
  252.                 if (prevpml == NULL)
  253.                     pmaplist = pml;
  254.                 else
  255.                     prevpml->pml_next = pml;
  256.                 free(t);
  257.             }
  258.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
  259.                 debugging) {
  260.                 fprintf(stderr, "svc_sendreply\n");
  261.                 abort();
  262.             }
  263.         }
  264.         break;
  265.  
  266.     case PMAPPROC_GETPORT:
  267.         /*
  268.          * Lookup the mapping for a program,version and return its port
  269.          */
  270.         if (!svc_getargs(xprt, xdr_pmap, ®))
  271.             svcerr_decode(xprt);
  272.         else {
  273.             fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
  274.             if (fnd)
  275.                 port = fnd->pml_map.pm_port;
  276.             else
  277.                 port = 0;
  278.             if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
  279.                 debugging) {
  280.                 fprintf(stderr, "svc_sendreply\n");
  281.                 abort();
  282.             }
  283.         }
  284.         break;
  285.  
  286.     case PMAPPROC_DUMP:
  287.         /*
  288.          * Return the current set of mapped program,version
  289.          */
  290.         if (!svc_getargs(xprt, xdr_void, NULL))
  291.             svcerr_decode(xprt);
  292.         else {
  293.             if ((!svc_sendreply(xprt, xdr_pmaplist,
  294.                 (caddr_t)&pmaplist)) && debugging) {
  295.                 fprintf(stderr, "svc_sendreply\n");
  296.                 abort();
  297.             }
  298.         }
  299.         break;
  300.  
  301.     case PMAPPROC_CALLIT:
  302.         /*
  303.          * Calls a procedure on the local machine.  If the requested
  304.          * procedure is not registered this procedure does not return
  305.          * error information!!
  306.          * This procedure is only supported on rpc/udp and calls via 
  307.          * rpc/udp.  It passes null authentication parameters.
  308.          */
  309.         callit(rqstp, xprt);
  310.         break;
  311.  
  312.     default:
  313.         svcerr_noproc(xprt);
  314.         break;
  315.     }
  316. }
  317.  
  318.  
  319. /*
  320.  * Stuff for the rmtcall service
  321.  */
  322. #define ARGSIZE 9000
  323.  
  324. typedef struct encap_parms {
  325.     u_long arglen;
  326.     char *args;
  327. };
  328.  
  329. static bool_t
  330. xdr_encap_parms(xdrs, epp)
  331.     XDR *xdrs;
  332.     struct encap_parms *epp;
  333. {
  334.  
  335.     return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
  336. }
  337.  
  338. typedef struct rmtcallargs {
  339.     u_long    rmt_prog;
  340.     u_long    rmt_vers;
  341.     u_long    rmt_port;
  342.     u_long    rmt_proc;
  343.     struct encap_parms rmt_args;
  344. };
  345.  
  346. static bool_t
  347. xdr_rmtcall_args(xdrs, cap)
  348.     register XDR *xdrs;
  349.     register struct rmtcallargs *cap;
  350. {
  351.  
  352.     /* does not get a port number */
  353.     if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
  354.         xdr_u_long(xdrs, &(cap->rmt_vers)) &&
  355.         xdr_u_long(xdrs, &(cap->rmt_proc))) {
  356.         return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
  357.     }
  358.     return (FALSE);
  359. }
  360.  
  361. static bool_t
  362. xdr_rmtcall_result(xdrs, cap)
  363.     register XDR *xdrs;
  364.     register struct rmtcallargs *cap;
  365. {
  366.     if (xdr_u_long(xdrs, &(cap->rmt_port)))
  367.         return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
  368.     return (FALSE);
  369. }
  370.  
  371. /*
  372.  * only worries about the struct encap_parms part of struct rmtcallargs.
  373.  * The arglen must already be set!!
  374.  */
  375. static bool_t
  376. xdr_opaque_parms(xdrs, cap)
  377.     XDR *xdrs;
  378.     struct rmtcallargs *cap;
  379. {
  380.  
  381.     return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
  382. }
  383.  
  384. /*
  385.  * This routine finds and sets the length of incoming opaque paraters
  386.  * and then calls xdr_opaque_parms.
  387.  */
  388. static bool_t
  389. xdr_len_opaque_parms(xdrs, cap)
  390.     register XDR *xdrs;
  391.     struct rmtcallargs *cap;
  392. {
  393.     register u_int beginpos, lowpos, highpos, currpos, pos;
  394.  
  395.     beginpos = lowpos = pos = xdr_getpos(xdrs);
  396.     highpos = lowpos + ARGSIZE;
  397.     while ((int)(highpos - lowpos) >= 0) {
  398.         currpos = (lowpos + highpos) / 2;
  399.         if (xdr_setpos(xdrs, currpos)) {
  400.             pos = currpos;
  401.             lowpos = currpos + 1;
  402.         } else {
  403.             highpos = currpos - 1;
  404.         }
  405.     }
  406.     xdr_setpos(xdrs, beginpos);
  407.     cap->rmt_args.arglen = pos - beginpos;
  408.     return (xdr_opaque_parms(xdrs, cap));
  409. }
  410.  
  411. /*
  412.  * Call a remote procedure service
  413.  * This procedure is very quiet when things go wrong.
  414.  * The proc is written to support broadcast rpc.  In the broadcast case,
  415.  * a machine should shut-up instead of complain, less the requestor be
  416.  * overrun with complaints at the expense of not hearing a valid reply ...
  417.  *
  418.  * This now forks so that the program & process that it calls can call 
  419.  * back to the portmapper.
  420.  */
  421. static
  422. callit(rqstp, xprt)
  423.     struct svc_req *rqstp;
  424.     SVCXPRT *xprt;
  425. {
  426.     struct rmtcallargs a;
  427.     struct pmaplist *pml;
  428.     u_short port;
  429.     struct sockaddr_in me;
  430.     int pid, socket = -1;
  431.     CLIENT *client;
  432.     struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
  433.     struct timeval timeout;
  434.     union wait pinfo;
  435.     char buf[ARGSIZE];
  436.  
  437.     timeout.tv_sec = 5;
  438.     timeout.tv_usec = 0;
  439.     a.rmt_args.args = buf;
  440.     if (!svc_getargs(xprt, xdr_rmtcall_args, &a))
  441.         return;
  442.     if ((pml = find_service(a.rmt_prog, a.rmt_vers, IPPROTO_UDP)) == NULL)
  443.         return;
  444.     /*
  445.      * fork a child to do the work.  Parent immediately returns.
  446.      * Child exits upon completion.
  447.      */
  448.     if ((pid = fork()) != 0) {
  449.         if (debugging && (pid < 0)) {
  450.             fprintf(stderr, "portmap CALLIT: cannot fork.\n");
  451.         }
  452.         /* reap previous forks. */
  453.         for (; pid>0; pid = wait3(&pinfo, WNOHANG, (struct rusage *)0));
  454.         return;
  455.     }
  456.     port = pml->pml_map.pm_port;
  457.     get_myaddress(&me);
  458.     me.sin_port = htons(port);
  459.     client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &socket);
  460.     if (client != (CLIENT *)NULL) {
  461.         if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
  462.             client->cl_auth = authunix_create(au->aup_machname,
  463.                au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
  464.         }
  465.         a.rmt_port = (u_long)port;
  466.         if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
  467.             xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
  468.             svc_sendreply(xprt, xdr_rmtcall_result, &a);
  469.         }
  470.         AUTH_DESTROY(client->cl_auth);
  471.         clnt_destroy(client);
  472.     }
  473.     (void)close(socket);
  474.     exit(0);
  475. }
  476.